/*
	GadgetCloak.cpp
	(c)2000 Palestar, Richard Lyle
*/


#include "Debug/Assert.h"
#include "Math/Helpers.h"
#include "NounShip.h"
#include "NounBeacon.h"
#include "GadgetCloak.h"
#include "GameContext.h"
#include "VerbGadgetOff.h"

// if non-zero, then beacons can't be cloaked
#define DISABLE_BEACON_CLOAKING		0

//----------------------------------------------------------------------------

IMPLEMENT_ABSTRACT_FACTORY( GadgetCloak, NounGadget ); 
REGISTER_FACTORY_KEY( GadgetCloak, 4137086329828747054 );

BEGIN_ABSTRACT_PROPERTY_LIST( GadgetCloak, NounGadget );
	ADD_TRANSMIT_UPDATE_PROPERTY( m_fCloak );
	ADD_TRANSMIT_UPDATE_PROPERTY( m_fSubVisibility );
END_PROPERTY_LIST();

GadgetCloak::GadgetCloak() : m_nEnergyTick( 0 )
{
	m_fCloak = 0.0f;
	m_fSubVisibility = 0.0f;
}

//----------------------------------------------------------------------------

void GadgetCloak::setup()
{
	NounGadget::setup();

	m_fCloak = 0.0f;
	m_fSubVisibility = 0.0f;
	m_nEnergyTick = 0;
}

void GadgetCloak::initialize()
{
	NounGadget::initialize();

	m_nEnergyTick = 0;

	NounShip * pParent = WidgetCast<NounShip>( parent() );
	if ( pParent != NULL )
	{
        if ( active() )
			pParent->addFlags( NounShip::FLAG_CLOAKED );
		else
			pParent->clearFlags( NounShip::FLAG_CLOAKED );
	}
}

//----------------------------------------------------------------------------

NounGadget::Type GadgetCloak::type() const
{
	return SPECIAL_DEFENSIVE;
}

dword GadgetCloak::hotkey() const
{
	return 'V';
}

bool GadgetCloak::usable( Noun * pTarget, bool shift ) const
{
	NounShip * pShip = WidgetCast<NounShip>( parent() );
	if ( pShip == NULL )
		return false;		// cloaking device only works for ships..
	if ( active() )
		return true;		// you can always turn it off..
	if ( isJumping() )
		return false;		// ship is currently jumping, no cloaking..
	if ( destroyed() )	
		return false;		// device is destroyed
	return true;
}

bool GadgetCloak::useActive() const
{
	// added fix so device can't be removed while we still are uncloaking the ship, leaving the cloaked flag turned on the ship
	return active() || isCloaked();
}

void GadgetCloak::use( dword when, Noun * pTarget, bool shift)
{
	// create the use effect
	createUseEffect();
	// toggle the active state
	setFlags( FLAG_ACTIVE, !active() );
	if ( active() )
		m_nEnergyTick = when;
	message( CharString().format( "<color;ffffff>Tactical: %s %s.", name(), active() ? "Active" : "Inactive" ) ); 
}

int GadgetCloak::useEnergy( dword nTick, int energy )
{ 
	NounShip * pShip = WidgetCast<NounShip>( parent() );
	if ( pShip == NULL )
		return energy;

	if ( m_nEnergyTick == 0 )
		m_nEnergyTick = nTick;		// first time updating this gadget, set initialize the energy tick to the current tick..

	int nElapsed = nTick - m_nEnergyTick;
	m_nEnergyTick = nTick;

	if ( active() )
	{
		// use energy for the cloaking device
		energy -= (pShip->cloakEnergyModifier() * energyCost()) * nElapsed;
		if ( isLocal() && (energy < 0 || isJumping() || destroyed()) )
		{
			message( CharString().format( "<color;ffff66>Engineering: %s Offline.", name() ) );
			Verb::Ref( new VerbGadgetOff( this ) );
		}

		// get the ship signature and ECM amount
		float fCloak = pShip->signature();
		// decrease signature covered when device is damaged
		fCloak -= fCloak * damageRatio();

#if DISABLE_BEACON_CLOAKING
		// remove the signature from any attached beacons... beacons are the only thing that 
		// can make a cloaked ship visible now.
		for(int i=0;i<pShip->childCount();i++)
			if ( WidgetCast<NounBeacon>( pShip->child(i) ) )
				fCloak -= ((NounBeacon *)pShip->child(i))->baseSignature();
#endif

		float fCloakRate = cloakRate() * (TICK_DURATION_S * nElapsed);
		fCloakRate *= pShip->cloakModifier();

		m_fSubVisibility += Min( pShip->visibility(), fCloakRate );
		m_fCloak += Min( fCloak, fCloakRate );

		// set the cloaking flag
		pShip->addFlags( NounShip::FLAG_CLOAKED );
	}
	else if ( pShip->testFlags( NounShip::FLAG_CLOAKED) )
	{
		float fCloakRate = uncloakRate() * (TICK_DURATION_S * nElapsed);
		fCloakRate *= pShip->cloakModifier();

		m_fSubVisibility = Max( m_fSubVisibility - fCloakRate, 0.0f );
		m_fCloak -= fCloakRate;

		// clear the cloaking flag
		if ( m_fCloak <= 0.0f )
		{
			pShip->clearFlags( NounShip::FLAG_CLOAKED );
			m_fCloak = 0.0f;
			m_fSubVisibility = 0.0f;
		}
	}

	return energy;
}

bool GadgetCloak::updateLogic()
{
	NounShip * pShip = WidgetCast<NounShip>( parent() );
	if (! pShip )
		return false;
	
	switch( pShip->command() )
	{
	case NounShip::EVADE:
		// turn on cloak
		if (!useActive() )
			pShip->useGadget( this, NULL, false );		
		break;
	default:
		// turn off cloak
		if ( useActive() )
			pShip->useGadget( this, NULL, false );
		break;
	}

	return true;
}

//----------------------------------------------------------------------------
// EOF
